/// The type of a directory metadata object: `(uuua(ayay))`
pub type DirmetaVariantType = (u32, u32, u32, Vec<(Vec<u8>, Vec<u8>)>);
+
+/// Parsed representation of directory metadata.
+pub struct DirMetaParsed {
+ /// The user ID.
+ pub uid: u32,
+ /// The group ID.
+ pub gid: u32,
+ /// The Unix mode, including file type flag.
+ pub mode: u32,
+ /// Extended attributes.
+ pub xattrs: Vec<(Vec<u8>, Vec<u8>)>,
+}
+
+impl DirMetaParsed {
+ /// Parse a directory metadata variant; must be of type `(uuua(ayay))`.
+ pub fn from_variant(
+ v: &glib::Variant,
+ ) -> Result<DirMetaParsed, glib::variant::VariantTypeMismatchError> {
+ let (uid, gid, mode, xattrs) = v.try_get::<crate::DirmetaVariantType>()?;
+ Ok(DirMetaParsed {
+ uid: u32::from_be(uid),
+ gid: u32::from_be(gid),
+ mode: u32::from_be(mode),
+ xattrs,
+ })
+ }
+}
);
}))
}
+
+ /// Load and parse directory metadata.
+ /// In particular, uid/gid/mode are stored in big-endian format; this function
+ /// converts them to host native endianness.
+ pub fn read_dirmeta(&self, checksum: &str) -> Result<crate::DirMetaParsed, glib::Error> {
+ let v = self.load_variant(crate::ObjectType::DirMeta, checksum)?;
+ // Safety: We know the variant type will match since we just passed it above
+ Ok(crate::DirMetaParsed::from_variant(&v).unwrap())
+ }
}
}
#[test]
-fn should_traverse_commit() {
+fn repo_traverse_and_read() {
let test_repo = TestRepo::new();
let checksum = test_repo.test_commit("test");
),
objects
);
+
+ let dirmeta = test_repo
+ .repo
+ .read_dirmeta("ad49a0f4e3bc165361b6d17e8a865d479b373ee67d89ac6f0ce871f27da1be6d")
+ .unwrap();
+ // Right now, the uid/gid are actually that of the test runner
+ assert_eq!(dirmeta.mode, 0o40750);
}
#[test]